# -*- coding: utf-8 -*-
# @Author  : CaoHan
# @Time    : 2024/2/4 11:04

from matplotlib import pyplot as plt
import numpy as np
import json
import seaborn as sns
from scipy.interpolate import make_interp_spline

plt.rc("font",family='STHeiti')
plt.rcParams.update({'font.size': 13})  # 设置全局默认字体大小

from ds.enumClass import OffloadDecision
from ds.uav import BatteryJ, FLOPS
from mpl_toolkits.mplot3d import Axes3D
req_num = 35087

def plotAll():
    with open('../data/150_30/ECSOA.json', mode='r') as file:
        ECSOA = json.load(file)
    with open('../data/150_30/LOCAL.json', mode='r') as file:
        LOCAL = json.load(file)
    with open('../data/150_30/EARS.json', mode='r') as file:
        EARS = json.load(file)
    with open('../data/150_30/OFFLOAD_ALL.json', mode='r') as file:
        OFFLOAD_ALL = json.load(file)
    with open('../data/150_30/SCORE.json', mode='r') as file:
        SCORE = json.load(file)
    with open('../data/150_30/FAAS_HOUSE.json', mode='r') as file:
        FAAS_HOUSE = json.load(file)
    with open('../data/150_30/RANDOM.json', mode='r') as file:
        RANDOM = json.load(file)
    with open('../data/150_30/ecsoa_nsga2_f1.json', mode='r') as file:
        data_dict_f1 = json.load(file)
    # 获取各个列表
    f1_energy = data_dict_f1['X']
    f1_rej = np.array(data_dict_f1['Y']) / req_num
    # ECSOA_NSGA2
    plt.scatter(f1_energy, f1_rej, color='y')
    plt.annotate('ECSOA', (ECSOA['avgOnTimeRatio'][-1], ECSOA['rejection_list'][-1]/req_num), color='y')
    # local
    plt.scatter(LOCAL['avgOnTimeRatio'][-1], LOCAL['rejection_list'][-1]/req_num, color='g')
    plt.annotate('Local', (LOCAL['avgOnTimeRatio'][-1], LOCAL['rejection_list'][-1]/req_num), color='g')
    # offload all
    plt.scatter(OFFLOAD_ALL['avgOnTimeRatio'][-1], OFFLOAD_ALL['rejection_list'][-1]/req_num, color='b')
    plt.annotate('LowRes', (OFFLOAD_ALL['avgOnTimeRatio'][-1], OFFLOAD_ALL['rejection_list'][-1]/req_num), color='b')
    # ears
    plt.scatter(EARS['avgOnTimeRatio'][-1], EARS['rejection_list'][-1]/req_num, color='r')
    plt.annotate('EAFS', (EARS['avgOnTimeRatio'][-1], EARS['rejection_list'][-1]/req_num), color='r')
    # score
    plt.scatter(SCORE['avgOnTimeRatio'][-1], SCORE['rejection_list'][-1]/req_num, color='m')
    plt.annotate('Score', (SCORE['avgOnTimeRatio'][-1], SCORE['rejection_list'][-1]/req_num), color='m')
    # random
    plt.scatter(RANDOM['avgOnTimeRatio'][-1], RANDOM['rejection_list'][-1]/req_num, color='c')
    plt.annotate('Random', (RANDOM['avgOnTimeRatio'][-1], RANDOM['rejection_list'][-1]/req_num), color='c')
    # faas house
    plt.scatter(FAAS_HOUSE['avgOnTimeRatio'][-1], FAAS_HOUSE['rejection_list'][-1]/req_num, color='purple')
    plt.annotate('FaasHouse', (FAAS_HOUSE['avgOnTimeRatio'][-1], FAAS_HOUSE['rejection_list'][-1]/req_num), color='purple')
    # plot figs
    plt.xlabel('平均开机时间比率')
    plt.ylabel('函数拒绝率')
    plt.show()


def plotAlgoOffloading():
    getAlgoDataAndPlotCurve('offloading_list')
    plt.xlabel("t/s")
    plt.ylabel("Offloading")
    plt.legend()
    plt.ticklabel_format(style='sci', axis='both', scilimits=(0, 0))
    plt.show()


def plotAlgoConsumeEnergyCurve():
    # 使用json模块读取JSON文件
    getAlgoDataAndPlotCurve('consume_energy_list')
    plt.xlabel("t/s")
    plt.ylabel("Total Energy Consumption/J")
    plt.legend()
    plt.ticklabel_format(style='sci', axis='both', scilimits=(0, 0))
    plt.show()


def getAlgoDataAndPlotCurve(list_name):
    # 使用json模块读取JSON文件
    with open('../data/150_30/ECSOA.json', mode='r') as file:
        ECSOA = json.load(file)
    with open('../data/150_30/LOCAL.json', mode='r') as file:
        LOCAL = json.load(file)
    with open('../data/150_30/EARS.json', mode='r') as file:
        EARS = json.load(file)
    with open('../data/150_30/OFFLOAD_ALL.json', mode='r') as file:
        OFFLOAD_ALL = json.load(file)
    with open('../data/150_30/SCORE.json', mode='r') as file:
        SCORE = json.load(file)
    with open('../data/150_30/FAAS_HOUSE.json', mode='r') as file:
        FAAS_HOUSE = json.load(file)
    with open('../data/150_30/RANDOM.json', mode='r') as file:
        RANDOM = json.load(file)
    ECSOA_X = np.array(ECSOA['plot_x'])
    LOCAL_X = np.array(LOCAL['plot_x'])
    EARS_X = np.array(EARS['plot_x'])
    OFFLOAD_ALL_X = np.array(OFFLOAD_ALL['plot_x'])
    SCORE_X = np.array(SCORE['plot_x'])
    FAAS_HOUSE_X = np.array(FAAS_HOUSE['plot_x'])
    RANDOM_X = np.array(RANDOM['plot_x'])

    ECSOA_Y = np.array(ECSOA[list_name])
    LOCAL_Y = np.array(LOCAL[list_name])
    EARS_Y = np.array(EARS[list_name])
    OFFLOAD_ALL_Y = np.array(OFFLOAD_ALL[list_name])
    SCORE_Y = np.array(SCORE[list_name])
    FAAS_HOUSE_Y = np.array(FAAS_HOUSE[list_name])
    RANDOM_Y = np.array(RANDOM[list_name])

    # plt.plot(ECSOA_X, ECSOA_Y, c='k', ls='-.', marker='.', mfc='b', mec='y', mew=1, label='ECSOA')
    # plt.plot(LOCAL_X, LOCAL_Y, c='k', ls='--', marker='.', mfc='b', mec='g', mew=1, label='Local')
    # plt.plot(EARS_X, EARS_Y, c='k', ls='-.', marker='.', mfc='b', mec='r', mew=1, label='EAFS')
    # plt.plot(OFFLOAD_ALL_X, OFFLOAD_ALL_Y, c='k', ls='--', marker='.', mfc='b', mec='b', mew=1, label='LowRes')
    # plt.plot(SCORE_X, SCORE_Y, c='k', ls='-.', marker='.', mfc='b', mec='m', mew=1, label='Score')
    # plt.plot(FAAS_HOUSE_X, FAAS_HOUSE_Y, c='k', ls='--', marker='.', mfc='b', mec='c', mew=1, label='FaasHouse')
    # plt.plot(RANDOM_X, RANDOM_Y, c='k', ls='-.', marker='.', mfc='b', mec='purple', mew=1, label='Random')
    plt.plot(ECSOA_X, ECSOA_Y, c='y', lw=3, label='ECSOA')
    plt.plot(LOCAL_X, LOCAL_Y, c='g', lw=3, label='Local')
    plt.plot(EARS_X, EARS_Y, c='r', lw=3, label='EAFS')
    plt.plot(OFFLOAD_ALL_X, OFFLOAD_ALL_Y, c='b', lw=3, label='LowRes')
    plt.plot(SCORE_X, SCORE_Y, c='m', lw=3, label='Score')
    plt.plot(FAAS_HOUSE_X, FAAS_HOUSE_Y, c='c', lw=3, label='FaasHouse')
    plt.plot(RANDOM_X, RANDOM_Y, c='purple', lw=3, label='Random')


def getAlgoDataAndPlotBar(list_name):
    with open('../data/150_30/ECSOA.json', mode='r') as file:
        ECSOA = json.load(file)
    with open('../data/150_30/LOCAL.json', mode='r') as file:
        LOCAL = json.load(file)
    with open('../data/150_30/EARS.json', mode='r') as file:
        EARS = json.load(file)
    with open('../data/150_30/OFFLOAD_ALL.json', mode='r') as file:
        OFFLOAD_ALL = json.load(file)
    with open('../data/150_30/SCORE.json', mode='r') as file:
        SCORE = json.load(file)
    with open('../data/150_30/FAAS_HOUSE.json', mode='r') as file:
        FAAS_HOUSE = json.load(file)
    with open('../data/150_30/RANDOM.json', mode='r') as file:
        RANDOM = json.load(file)
    algorithms = ['ECSOA', 'Local', 'EAFS', 'LowRes', 'Score', 'FaasHouse', 'Random']
    values = [ECSOA[list_name][-1], LOCAL[list_name][-1], EARS[list_name][-1], OFFLOAD_ALL[list_name][-1],
              SCORE[list_name][-1], FAAS_HOUSE[list_name][-1], RANDOM[list_name][-1]]
    colors = ['y', 'g', 'r', 'b', 'm', 'c', 'purple']
    # 绘制柱状图
    x = np.arange(len(algorithms))
    plt.bar(x, values, color=colors, edgecolor='black', width=0.6)
    plt.xticks(np.arange(7), algorithms, fontsize=10)


def getAlgoDataAndPlotBox(list_name, ylabel):
    # 使用json模块读取JSON文件
    with open('../data/150_30/ECSOA.json', mode='r') as file:
        ECSOA = json.load(file)
    with open('../data/150_30/LOCAL.json', mode='r') as file:
        LOCAL = json.load(file)
    with open('../data/150_30/EARS.json', mode='r') as file:
        EARS = json.load(file)
    with open('../data/150_30/OFFLOAD_ALL.json', mode='r') as file:
        OFFLOAD_ALL = json.load(file)
    with open('../data/150_30/SCORE.json', mode='r') as file:
        SCORE = json.load(file)
    with open('../data/150_30/FAAS_HOUSE.json', mode='r') as file:
        FAAS_HOUSE = json.load(file)
    with open('../data/150_30/RANDOM.json', mode='r') as file:
        RANDOM = json.load(file)
    ECSOA_Y = np.array(ECSOA[list_name])
    LOCAL_Y = np.array(LOCAL[list_name])
    EARS_Y = np.array(EARS[list_name])
    OFFLOAD_ALL_Y = np.array(OFFLOAD_ALL[list_name])
    SCORE_Y = np.array(SCORE[list_name])
    FAAS_HOUSE_Y = np.array(FAAS_HOUSE[list_name])
    RANDOM_Y = np.array(RANDOM[list_name])

    data = [ECSOA_Y, LOCAL_Y, EARS_Y, OFFLOAD_ALL_Y, SCORE_Y, FAAS_HOUSE_Y, RANDOM_Y]

    algorithms = ['ECSOA', 'Local', 'EAFS', 'LowRes', 'Score', 'FaasHouse', 'Random']
    colors = ['y', 'g', 'r', 'b', 'm', 'c', 'purple']
    # 绘制箱线图
    fig, ax = plt.subplots(figsize=(10, 6))
    box = ax.boxplot(data, patch_artist=True, vert=True, widths=0.6)
    # 设置箱子的颜色
    for patch, color in zip(box['boxes'], colors):
        patch.set_facecolor(color)
    # 添加标签
    ax.set_xticks(range(1, len(algorithms) + 1))
    ax.set_xticklabels(algorithms, fontsize=12)
    ax.set_ylabel(ylabel, fontsize=14)


def plotAlgoRemainFlops():
    getAlgoDataAndPlotBox('remain_FLOPS_list', 'Remain FLOPS')
    # 显示图形
    plt.grid(axis='y', linestyle='--', alpha=0.7)
    plt.tight_layout()
    plt.show()


def plotAlgoIdleContainer():
    getAlgoDataAndPlotBox('idle_container_list', 'Idle Container')
    # 显示图形
    plt.grid(axis='y', linestyle='--', alpha=0.7)
    plt.tight_layout()
    plt.show()


def plotAlgoRemainEnergy():
    getAlgoDataAndPlotCurve('remain_energy_list')
    plt.xlabel("t/s")
    plt.ylabel("Battery Remain Energy")
    plt.legend()
    plt.ticklabel_format(style='sci', axis='both', scilimits=(0, 0))
    plt.show()


def plotAlgoColdStart():
    getAlgoDataAndPlotCurve('coldStart_list')
    plt.xlabel("t/s")
    plt.ylabel("Cold Start")
    plt.legend()
    plt.ticklabel_format(style='sci', axis='both', scilimits=(0, 0))
    plt.show()


def plotAlgoConsumeEnergyBar():
    getAlgoDataAndPlotBar('consume_energy_list')
    plt.ylim(8.5e6, None)
    plt.ylabel("Total Energy Consumption/J")
    plt.show()


def plotAlgoAvgLatency():
    getAlgoDataAndPlotBar('avgLatency')
    plt.ylim(5, None)
    plt.ylabel("Average Latency/s")
    plt.show()


def plotAlgoAvgOnTimeRatio():
    getAlgoDataAndPlotBar('avgOnTimeRatio')
    plt.ylim(0.8, None)
    plt.ylabel("平均开机时间比率")
    plt.show()


def plotAlgoRej():
    getAlgoDataAndPlotCurve('rejection_list')
    plt.xlabel("时间/s")
    plt.ylabel("累计拒绝数")
    plt.legend()
    plt.ticklabel_format(style='sci', axis='both', scilimits=(0, 0))
    plt.show()


def plotCSOff():
    # 导入数据
    with open('../data/150_30/ECSOA.json', mode='r') as file:
        ECSOA = json.load(file)
    with open('../data/150_30/LOCAL.json', mode='r') as file:
        LOCAL = json.load(file)
    with open('../data/150_30/EARS.json', mode='r') as file:
        EARS = json.load(file)
    with open('../data/150_30/OFFLOAD_ALL.json', mode='r') as file:
        OFFLOAD_ALL = json.load(file)
    with open('../data/150_30/SCORE.json', mode='r') as file:
        SCORE = json.load(file)
    with open('../data/150_30/FAAS_HOUSE.json', mode='r') as file:
        FAAS_HOUSE = json.load(file)
    with open('../data/150_30/RANDOM.json', mode='r') as file:
        RANDOM = json.load(file)
    # 导入数据
    x = np.arange(7)
    x1 = [ECSOA['coldStartNum'][0], LOCAL['coldStartNum'][0], EARS['coldStartNum'][0], OFFLOAD_ALL['coldStartNum'][0],
          SCORE['coldStartNum'][0], FAAS_HOUSE['coldStartNum'][0], RANDOM['coldStartNum'][0]]
    x2 = [ECSOA['offloadingNum'][0], LOCAL['offloadingNum'][0], EARS['offloadingNum'][0],
          OFFLOAD_ALL['offloadingNum'][0], SCORE['offloadingNum'][0], FAAS_HOUSE['offloadingNum'][0],
          RANDOM['offloadingNum'][0]]
    # 设置所需参数
    total_width, n = 0.7, 2  # （柱状图的默认宽度值为 0.8）
    width = total_width / n
    x = x - (total_width - width) / 2  # 现在的x是每个并列柱的第一柱的中心横坐标
    # 绘制图
    plt.bar(x, x1, width=width, label='Cold Start Number', fc='b')
    plt.bar(x + width, x2, width=width, label='Offloading Number', fc='m')
    # plt.bar(x + 2 * width, x3, width=width, label='english', fc='y')
    plt.xticks(np.arange(7), ['ECSOA', 'Local', 'EAFS', 'LowRes', 'Score', 'FaasHouse', 'Random'])
    plt.legend()  # 添加图例
    plt.show()


def plotDataDistri():
    with open('../data/150_30/ecsoa_nsga2_f1.json', mode='r') as file:
        data_dict = json.load(file)
    solu = np.array(data_dict['solution'])
    thre = solu[:, 0]
    threBat = solu[:, 1]
    print(thre.tolist())
    print(threBat.tolist())
    print(len(thre))

    # 设置全局字体大小
    plt.rcParams.update({'font.size': 13.5})
    # 绘制核密度估计曲线
    sns.kdeplot(thre, color='salmon', bw_adjust=0.25, clip=(0, 10), linewidth=2)
    plt.xlabel('Threshold 1')
    plt.ylabel('Density')
    plt.show()
    # 绘制核密度估计曲线
    sns.kdeplot(threBat, color='salmon', bw_adjust=0.10, clip=(0, 120), linewidth=2)
    plt.xlabel('Threshold 2')
    plt.ylabel('Density')
    plt.show()


def plotECSOA():
    plotECSOARej()
    plotECSOARemainE()
    plotECSOARemainFLOPS()
    plotECSOASpareNum()


def plotUAVs(ECSOA_X, ECSOA_Y):
    plt.plot(ECSOA_X, ECSOA_Y[0], c='y', label='$ES_{1}$', linewidth=2)
    plt.plot(ECSOA_X, ECSOA_Y[1], c='g', label='$ES_{2}$', linewidth=2)
    plt.plot(ECSOA_X, ECSOA_Y[2], c='r', label='$ES_{3}$', linewidth=2)
    plt.plot(ECSOA_X, ECSOA_Y[3], c='b', label='$ES_{4}$', linewidth=2)
    plt.plot(ECSOA_X, ECSOA_Y[4], c='m', label='$ES_{5}$', linewidth=2)
    plt.plot(ECSOA_X, ECSOA_Y[5], c='c', label='$ES_{6}$', linewidth=2)


def plotECSOASpareNum():
    # 使用json模块读取JSON文件
    with open('../data/150_30/ECSOA.json', mode='r') as file:
        ECSOA = json.load(file)
    ECSOA_X = np.array(ECSOA['plot_x'])
    ECSOA_Y = np.array(ECSOA['uav_idleCNum_list'])
    plotUAVs(ECSOA_X, ECSOA_Y)
    plt.xlabel("t/s", fontsize=13.5)
    plt.ylabel("Idle containers", fontsize=13.5)

    plt.legend()
    plt.ticklabel_format(style='sci', axis='x', scilimits=(0, 0))
    plt.show()


def plotECSOARej():
    # 使用json模块读取JSON文件
    with open('../data/150_30/ECSOA.json', mode='r') as file:
        ECSOA = json.load(file)
    ECSOA_X = np.array(ECSOA['plot_x'])
    ECSOA_Y = np.array(ECSOA['uav_rej_list'])
    plotUAVs(ECSOA_X, ECSOA_Y)
    plt.xlabel("t/s")
    plt.ylabel("Rejection")
    plt.legend()
    plt.ticklabel_format(style='sci', axis='x', scilimits=(0, 0))
    plt.show()


def plotECSOARemainE():
    # 使用json模块读取JSON文件
    with open('../data/150_30/ECSOA.json', mode='r') as file:
        ECSOA = json.load(file)
    ECSOA_X = ECSOA['plot_x']
    ECSOA_Y = ECSOA['uav_remainE_list']
    x = []
    y = [[], [], [], [], [], []]
    for i in range(len(ECSOA_X)):
        if i % 25 == 0:
            x.append(ECSOA_X[i])
            for j in range(len(ECSOA_Y)):
                y[j].append(ECSOA_Y[j][i])
    plotUAVs(x, y)
    plt.xlabel("t/s", fontsize=13.5)
    plt.ylabel("Remaining battery capacity/J", fontsize=13.5)
    plt.legend()
    plt.ticklabel_format(style='sci', axis='both', scilimits=(0, 0))
    plt.show()


def plotECSOARemainFLOPS():
    # 使用json模块读取JSON文件
    with open('../data/150_30/ECSOA.json', mode='r') as file:
        ECSOA = json.load(file)
    ECSOA_X = np.array(ECSOA['plot_x'])
    ECSOA_Y = np.array(ECSOA['uav_remainFLOPS_list'])
    plotUAVs(ECSOA_X, ECSOA_Y)
    plt.xlabel("t/s", fontsize=13.5)
    plt.ylabel("Remain FLOPS/G", fontsize=13.5)

    plt.legend()
    plt.ticklabel_format(style='sci', axis='x', scilimits=(0, 0))
    plt.show()


if __name__ == "__main__":
    # -------------画图-------------
    # # 主要的两个对比指标
    # plotAll()
    # plotDataDistri()
    # plotAlgoRej()
    plotAlgoAvgOnTimeRatio()
    # # 其他对比指标：能耗
    # plotAlgoConsumeEnergyCurve()
    # plotAlgoConsumeEnergyBar()
    # plotAlgoRemainEnergy()
    # # 其他对比指标：延迟
    # plotAlgoAvgLatency()
    # # 其他对比指标：冷启动和卸载
    # plotCSOff()
    # plotAlgoColdStart()
    # plotAlgoOffloading()
    # # 其他对比指标：资源状态
    # plotAlgoRemainFlops()
    # plotAlgoIdleContainer()
    # # ECSOA算法运行过程的刻画
    # plotECSOA()

